package com.atguigu.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author 伟哥
 * @date 2021-05-05 16:22
 *
 * 事务的传播
 */
@Service
public class MulService {

    @Autowired
    private BookService bookService;

    /**
     * 事务传播行为演示，多事务操作，出错之后，是否需要一起回滚
     *
     *  回滚，不回滚：【都需要设置】
     *  传播行为：用来设置，这个事务方法是否和大事务共享一个事务（使用同一条连接）
     *
     *  目前这个方法有3个事务：
     *      方法本身mulTx、checkout、updateBookPrice
     *      这3个事务，可以分别设置自身的传播行为，
     *      实例1：
     *      @Transactional 【这里不设置，默认是Propagation.REQUIRED】
     *      public void mulTx(){
     *
     *
     *      @Transactional(propagation = Propagation.REQUIRED)【和大事务共用连接】
     *     public void updateBookPrice(String isbn,int price){
     *
     *     @Transactional(propagation = Propagation.REQUIRED)【和大事务共用连接】
     *     public void checkout(String username,String isbn) {
     *
     *     现在，checkout、updateBookPrice这2个事务，需要一个事务，它们两个将会在，大事务mulTx内部运行，也就是3个事务，在一条数据库连接上运行，出现异常，3个事务，一起回滚。
     *
     *
     *     实例2：
     *     @Transactional 【这里不设置，默认是Propagation.REQUIRED】
     *     public void mulTx(){
     *
     *     @Transactional(propagation = Propagation.REQUIRES_NEW)【开新连接】
     *     public void checkout(String username,String isbn) {
     *
     *     @Transactional(propagation = Propagation.REQUIRED)【和大事务共用连接】
     *     public void updateBookPrice(String isbn,int price){
     *
     *     现在，updateBookPrice和大事务multx共用连接，updateBookPricet中出现异常，multx、updateBookPrice一起回滚；checkout是新开的连接，所以数据提交修改成功，不会回滚
     *
     *     实例3：★★★
     *     @Transactional 【这里不设置，默认是Propagation.REQUIRED】
     *     public void mulTx(){
     *
     *     @Transactional(propagation = Propagation.REQUIRED)【和大事务共用连接】
     *     public void checkout(String username,String isbn) {
     *
     *     @Transactional(propagation = Propagation.REQUIRES_NEW)【开新连接】
     *     public void updateBookPrice(String isbn,int price){
     *     现在，checkout和大事务multx共用连接；updateBookPricet新开一条数据库连接，updateBookPrice中出现异常，理应来说：updateBookPrice自己回滚，checkout和大事务multx共用连接，不会回滚。实则：3个事务一起回滚，为什么呢？
     *          因为updateBookPrice出现异常之后，把【异常向外抛出】，使大事务multx感知到了异常，也跟着updateBookPrice一起回滚，又因为checkout和大事务multx共用一个连接，所以也跟着一起回滚，最后3个事务一起回滚
     *
     *      实例4：
     *      @Transactional 【这里不设置，默认是Propagation.REQUIRED】
     *      public void mulTx(){
     *
     *      @Transactional(propagation = Propagation.REQUIRES_NEW)【开新连接】
     *      public void checkout(String username,String isbn) {
     *
     *      @Transactional(propagation = Propagation.REQUIRES_NEW)【开新连接】
     *      public void updateBookPrice(String isbn,int price){
     *
     *      现在，相当于3个事务，3条连接，互不相干。大事务multx，出现by zero异常，checkout、updateBookPrice都不会跟随大事务multx回滚
     *
     *      实例5：
     *      mulTx(){
     *
     *          //REQUIRED
     *          A(){
     *              //REQUIRES_NEW
     *              B(){}
     *              //REQUIRED
     *              C(){}
     *          }
     *
     *          //REQUIRES_NEW
     *          D(){
     *              //REQUIRES_NEW不崩，REQUIRED崩
     *              DABC(){}
     *              //REQUIRED
     *              E(){
     *                  //REQUIRES_NEW
     *                  F(){
     *                      int i = 1/0;【E崩、G崩（G还没运行）、A崩、C崩、DABC：REQUIRES_NEW不崩，REQUIRED崩】
     *                  }
     *              }
     *              //REQUIRES_NEW
     *              G(){}
     *          }
     *      }
     *
     *      int i = 1/0;【B成功、D整个分支下全部成功】
     *      任何处 崩，已经执行的REQUIRES_NEW都会成功；
     *
     *      ★★★子事务（REQUIRED），事务的属性都是继承于大事务，子事务的属性设置无效（例如：子事务的timeout）
     *      ★★★REQUIRES_NEW，事务的属性是自己的，属性设置有效
     *
     *      原理：★★★
     *          REQUIRED：将之前事务（大事务）的connection传递给这个方法使用（子事务）
     *          REQUIRES_NEW：这个方法直接使用新的connection
     */
    @Transactional
    public void mulTx(){
        bookService.checkout("Tom","ISBN-001");

        bookService.updateBookPrice("ISBN-002",998);

        int i = 10/0;
    }
}
